package biz

import (
	"context"
	"platform-sastay-file/internal/conf"
	"strings"

	"github.com/go-kratos/kratos/v2/errors"
	"github.com/go-kratos/kratos/v2/log"
)

var (
	ErrClusterNotFound = errors.NotFound("CLUSTER_NOT_FOUND", "没有可用集群")
)

type ClusterRepo interface {
	// TagUseNode 标记使用过的节点
	TagUseNode(ctx context.Context, clusterName, ip string) error
	// VoteRotateNode 轮询选举节点
	VoteRotateNode(ctx context.Context, clusterName string, nodes []string) (string, error)
}

type ClusterUsecase struct {
	log            *log.Helper
	conf           *conf.Biz
	domainNameRepo DomainNameRepo // 域名服务
	nodeRepo       NodeRepo       // 节点服务
	clusterRepo    ClusterRepo    // 集群服务
}

func NewClusterUsecase(logger log.Logger, conf *conf.Biz, domainNameRepo DomainNameRepo, nodeRepo NodeRepo, clusterRepo ClusterRepo) *ClusterUsecase {
	return &ClusterUsecase{
		log:            log.NewHelper(log.With(logger, "module", "usecase/cluster")),
		conf:           conf,
		domainNameRepo: domainNameRepo,
		nodeRepo:       nodeRepo,
		clusterRepo:    clusterRepo,
	}
}

// GetLoadBalanceURL 获取负载均衡url地址
func (c *ClusterUsecase) GetLoadBalanceURL(ctx context.Context, name string) (string, error) {
	nodes, err := c.nodeRepo.GetNodesByName(ctx, name)
	if err != nil {
		return "", err
	}
	clusterName := c.buildClusterNameTag(name)
	node, err := c.clusterRepo.VoteRotateNode(ctx, clusterName, nodes)
	if err != nil {
		return "", err
	}
	err = c.clusterRepo.TagUseNode(ctx, clusterName, node)
	if err != nil {
		return "", err
	}
	d, err := c.domainNameRepo.GetDomain(ctx, node)
	if err != nil {
		return "", err
	}
	return c.buildFileApiURL(d.DomainName), nil
}

// buildClusterNameTag 生成集群名称
func (c *ClusterUsecase) buildClusterNameTag(name string) string {
	return strings.Join([]string{c.conf.Etcd.ClusterTag, name}, ".")
}

// buildFileApiURL 生成文件接口url地址
func (c *ClusterUsecase) buildFileApiURL(domainName string) string {
	return strings.Join([]string{c.conf.FileApi.Proto, "//", domainName, c.conf.FileApi.Route}, "")
}
